package test.queue.core;

import java.util.EnumMap;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;

public class BufferManager {

    public static final boolean OFFERING_FAILED = false;
    public static final boolean OFFERING_SUCCESSFUL = true;
    private static BufferManager queueManager;
    private Map<QueueObjectType, QueueParameters> queueMap = new EnumMap<QueueObjectType, QueueParameters>(
	    QueueObjectType.class);

    private class QueueParameters{
	private Queue<Object> queue;
	private Criteria criteria;
	private FetcherController fetcher;

	public QueueParameters(Queue<Object> queue, Criteria criteria,
		FetcherController fetcher) {
	   this.queue = queue;
	   this.criteria = criteria;
	   this.fetcher = fetcher;
	}
    }

    public static BufferManager getInstance() {
	if (BufferManager.queueManager == null) {
	    BufferManager.queueManager = new BufferManager();
	}
	return BufferManager.queueManager;
    }


    public boolean offer(Object object, QueueObjectType objectType) {
	if (false == queueMap.containsKey(objectType)) {
	    return false;
	}

	QueueParameters qParam = queueMap.get(objectType);

	if (qParam.criteria.isOverloaded(qParam.queue) == Criteria.QUEUE_OVERLOADED) {
	    return BufferManager.OFFERING_FAILED;
	}

	boolean offerResult = qParam.queue.offer(object);

	if (offerResult == true) {
	    return BufferManager.OFFERING_SUCCESSFUL;
	}

	return BufferManager.OFFERING_FAILED;
    }

    public Object poll(QueueObjectType objectType) {

	if (false == queueMap.containsKey(objectType)) {
	    return null;
	}

	QueueParameters parameters = queueMap.get(objectType);
	Queue<Object> queue = parameters.queue;
	Object object = queue.poll();

	if (parameters.criteria.isUnderUtilized(queue) == Criteria.QUEUE_UNDER_UTILIZED) {
	    parameters.fetcher.startFetching(this);
	}

	return object;
    }

    public boolean queueExists(QueueObjectType objectType) {
	return queueMap.containsKey(objectType);
    }

    public void register(QueueObjectType objectType, FetcherController fetcher,
	    Criteria criteria) {
	Queue<Object> queue = new ConcurrentLinkedQueue<Object>();
	QueueParameters parameters = new QueueParameters(queue, criteria,
		fetcher);
	queueMap.put(objectType, parameters);
	fetcher.startFetching(this);
    }
}
